import { Component, cls, type StyledProps } from '@knno/jsx';
import { EventBus } from '../../tools/eventBus';
import { isDescendant } from '../../tools/utils';
import { DATA } from '../symbol';
import { type EditCommand, InlineEditor, InlineEditorProps, TOOLBAR_CHANGE } from './inlineEditor';
import { richEditorStyle } from './richEditor.css';
import { EditorToolbar, EditorToolbarProps } from './toolbar';

export { InlineEditor, InlineEditorProps, EditorToolbar, EditorToolbarProps };

export type RichEditorProps = StyledProps<RichEditor> & {
	source?: string;
	readOnly?: boolean;
	disabled?: boolean;
	onChange?: (this: RichEditor) => void;
	onFocus?: (this: RichEditor) => void;
	onBlur?: (this: RichEditor) => void;
};
export class RichEditor extends Component<RichEditorProps> {
	private [DATA]: {
		toolbar?: EditorToolbar;
		editor?: InlineEditor;
		eventBus: EventBus<EditCommand>;
	} = {
		eventBus: new EventBus<EditCommand>(),
	};
	private listenSelectionChange = () => {
		const selection = window.getSelection();
		if (!selection || selection.rangeCount < 1) return;
		const range = selection.getRangeAt(0);
		if (this[DATA].editor && isDescendant([this[DATA].editor.el], range.startContainer)) {
			if (this[DATA].editor.onSelectionChange()) {
				return;
			}
		}
		this[DATA].eventBus.publish(TOOLBAR_CHANGE, undefined);
	};
	protected render(): Node {
		return (
			<div class={cls(this.props.class, richEditorStyle)} style={this.props.style}>
				<EditorToolbar
					readOnly={this.props.readOnly || this.props.disabled}
					ref={(tb) => (this[DATA].toolbar = tb)}
				/>
				<div class="rich-text-box">
					<InlineEditor
						ref={(ed) => (this[DATA].editor = ed)}
						readOnly={this.props.readOnly}
						disabled={this.props.disabled}
						source={this.props.source}
						eventBus={this[DATA].eventBus}
						onConnected={() => {
							document.addEventListener('selectionchange', this.listenSelectionChange);
						}}
						onDisconnected={() => {
							document.removeEventListener('selectionchange', this.listenSelectionChange);
						}}
					/>
				</div>
			</div>
		);
	}
	constructor(props: RichEditorProps) {
		super(props);
		this[DATA].eventBus.subscribe(TOOLBAR_CHANGE, (evt, data) => {
			this[DATA].toolbar?.setData(data);
		});
	}

	onChange(handler: ((this: RichEditor) => void) | undefined): this {
		this.props.onChange = handler;
		return this;
	}

	onFocus(handler: ((this: RichEditor) => void) | undefined): this {
		this.props.onFocus = handler;
		return this;
	}

	onBlur(handler: ((this: RichEditor) => void) | undefined): this {
		this.props.onBlur = handler;
		return this;
	}

	setSource(html: string): this {
		this.props.source = html;
		return this;
	}

	get readOnly(): boolean {
		return this.props.readOnly ?? false;
	}

	setReadOnly(value: boolean): this {
		this.props.readOnly = value;
		this[DATA].toolbar?.setReadOnly(value);
		this[DATA].editor?.setReadOnly(value);
		return this;
	}

	get disabled(): boolean {
		return this.props.disabled ?? false;
	}

	setDisabled(value: boolean): this {
		this.props.disabled = value;
		this[DATA].toolbar?.setReadOnly(value);
		this[DATA].editor?.setDisabled(value);
		return this;
	}
}
